package cool.mtc.security.plugin.jwt;

import cool.mtc.core.util.DateUtil;
import io.jsonwebtoken.*;
import io.jsonwebtoken.impl.DefaultClaims;
import lombok.RequiredArgsConstructor;

import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.Key;
import java.time.Duration;
import java.time.LocalDateTime;
import java.util.Map;
import java.util.UUID;

/**
 * @author 明河
 */
@RequiredArgsConstructor
public class JwtTemplate {
    private final JwtProperties jwtProperties;

    public JwtInfo generate(Map<String, Object> data) {
        return this.generate(UUID.randomUUID().toString(), data);
    }

    public JwtInfo generate(Map<String, Object> data, Duration validDuration) {
        return this.generate(UUID.randomUUID().toString(), data, validDuration);
    }

    public JwtInfo generate(String id, Map<String, Object> data) {
        Claims claims = this.handleClaimsData(data);
        return this.generate(id, claims);
    }

    public JwtInfo generate(String id, Map<String, Object> data, Duration validDuration) {
        Claims claims = this.handleClaimsData(data, validDuration);
        return this.generate(id, claims);
    }

    public JwtInfo generate(String id, Claims claims) {
        String token = Jwts.builder()
                .setId(id)
                .addClaims(claims)
                .signWith(jwtProperties.getSignatureAlgorithm(), this.getKey())
                .compact();
        return new JwtInfo(id, token);
    }

    public Claims parse(String token) throws ExpiredJwtException, UnsupportedJwtException, MalformedJwtException, SignatureException, IllegalArgumentException {
        return Jwts.parser().setSigningKey(this.getKey()).parseClaimsJws(token).getBody();
    }

    /**
     * 处理载荷数据
     */
    private Claims handleClaimsData(Map<String, Object> data) {
        return handleClaimsData(data, jwtProperties.getValidDuration());
    }

    private Claims handleClaimsData(Map<String, Object> data, Duration validDuration) {
        Claims claims = new DefaultClaims();
        claims.putAll(data);
        LocalDateTime now = LocalDateTime.now();
        // 签发时间
        claims.setIssuedAt(DateUtil.localDateTimeToDate(now));
        // 过期时间
        LocalDateTime expiredDateTime = now.plusMinutes(validDuration.toMinutes());
        claims.setExpiration(DateUtil.localDateTimeToDate(expiredDateTime));
        return claims;
    }

    /**
     * 根据设置的秘钥及签名算法获取key
     */
    private Key getKey() {
        byte[] key_bytes = jwtProperties.getKey().getBytes(StandardCharsets.UTF_8);
        return new SecretKeySpec(key_bytes, jwtProperties.getSignatureAlgorithm().getJcaName());
    }
}
